package cnki.tpi.kbatis.sqlsession;


import cnki.tpi.kbatis.annotation.ID;
import cnki.tpi.kbatis.annotation.LongText;
import cnki.tpi.kbatis.annotation.Table;
import cnki.tpi.kbatis.config.Configuration;
import cnki.tpi.kbatis.config.MappedStatement;
import cnki.tpi.kbatis.executor.CacheExecutor;
import cnki.tpi.kbatis.executor.SimpleExecutor;
import cnki.tpi.kbatis.executor.iface.Executor;
import cnki.tpi.kbatis.utils.DataSourceUtil;
import com.kbase.jdbc.ResultSetImpl;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * @ClassName DefaultSqlSession
 * @Description
 * @Author 小黄
 * @Date 2019/11/15 20:01
 * @Version 1.0
 */
public class DefaultSqlSession implements SqlSession {

    private Configuration configuration;

    public DefaultSqlSession(Configuration configuration) {
        this.configuration = configuration;
    }

    @Override
    public <T> T selectOne(String statementId, Object param, Boolean isHighLight) {
        List<Object> list = this.selectList(statementId, param, isHighLight);
        if (list != null && list.size() == 1) {
            return (T) list.get(0);
        }
        return null;
    }

    @Override
    public <T> List<T> selectList(String statementId, Object param, Boolean isHighLight) {
        MappedStatement mappedStatementById = configuration.getMappedStatementById(statementId);
        Executor executor = new CacheExecutor(new SimpleExecutor());
        return executor.queryList(mappedStatementById, configuration, param, isHighLight);

    }

    @Override
    public Long getCount(String statementId, Object param) {
        MappedStatement mappedStatementById = configuration.getMappedStatementById(statementId);
        Executor executor = new CacheExecutor(new SimpleExecutor());
        return executor.queryRecordNumber(mappedStatementById, configuration, param);
    }

    @Override
    public Boolean executeInsert(String statementId, Object param) {
        return execute(statementId, param);
    }

    @Override
    public Boolean executeWithLongText(String statementId, Object param, String selectCondition) {
        //先将长文本字段对应的表字段名称和待插入的内容存到map 中
        Class<?> paramClass = param.getClass();
        Table table = paramClass.getAnnotation(Table.class);
        //长文本插入必须加上@table和@LongText注解
        if (table != null) {
            List<Field> fields = DataSourceUtil.getFields(paramClass);
            Map<String, String> map = new HashMap<>();
            String idColumn = "";
            if (fields != null && fields.size() > 0) {
                for (Field field : fields) {
                    field.setAccessible(true);
                    LongText longText = field.getAnnotation(LongText.class);
                    ID idAnnotation = field.getAnnotation(ID.class);
                    try {
                        if (idAnnotation != null) {
                            idColumn = idAnnotation.value();
                        }
                        if (longText != null) {
                            String fieldValue = (String) field.get(param);
                            String longTextValue = longText.value();
                            if (fieldValue != null && !fieldValue.trim().equals("")) {
                                map.put(longTextValue, fieldValue);
                            }
                        }
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
            //如果长文本字段插入内容都为null或者空串,只进行插入操作即可
            if (map.size() > 0) {
                StringBuilder sb = new StringBuilder("select * from ").append(table.value()).append(" where ");
                //通过传进来的条件查找出刚插入/更新的那条数据记录
                if (selectCondition != null && !selectCondition.trim().equals("")) {
                    Boolean flag = execute(statementId, param);
                    if (flag) {
                        sb.append(selectCondition);
                        updateLongText(sb.toString(), map);
                    }
                    return flag;
                } else {
                    //通过max(id)查找
                    synchronized (this) {
                        Boolean flag = execute(statementId, param);
                        if (flag) {
                            Integer id = getMaxId(idColumn, table.value());
                            if (id != 0) {
                                sb.append(idColumn).append(" = ").append(id);
                                updateLongText(sb.toString(), map);
                            }
                        }
                        return flag;
                    }
                }
            } else {
                return execute(statementId, param);
            }
        } else {
            return execute(statementId, param);
        }
    }

    @Override
    public Boolean executeDelete(String statementId, Object param) {
        return execute(statementId, param);
    }

    @Override
    public Boolean executeUpdate(String statementId, Object param) {
        return execute(statementId, param);
    }

    private Boolean execute(String statementId, Object param) {
        MappedStatement mappedStatementById = configuration.getMappedStatementById(statementId);
        Executor executor = new CacheExecutor(new SimpleExecutor());
        return executor.execute(mappedStatementById, configuration, param);
    }

    /**
     * 由于kbase支持的sql语句长度有限，直接使用insert或者update语句会自动截断导致语法出错，从而执行失败
     * 针对比较长的文本数据，先将基本信息插入或者更新，然后进行长文本字段的更新。
     *
     * @param sql 如：SELECT * FROM TPINEWS_METADATA WHERE SYS_FLD_SYSID=16
     */
    @Override
    public void updateLongText(String sql, Map<String, String> map) {
        ResultSetImpl rsi = null;
        Connection conn = null;
        Statement pst = null;
        try {
            conn = DataSourceUtil.getConnection(configuration);
            pst = conn.createStatement();
            rsi = (ResultSetImpl) pst.executeQuery(sql);
            rsi.last();
            for (Map.Entry<String, String> entry : map.entrySet()) {
                rsi.updateString(entry.getKey(), entry.getValue());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (rsi != null && !rsi.isClosed()) {
                    rsi.close();
                }
                if (pst != null && !pst.isClosed()) {
                    pst.close();
                }
                if (conn != null && !conn.isClosed()) {
                    conn.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public Integer getMaxId(String fieldName, String tableName) {
//        String sql = "select max(" + fieldName + ") from " + tableName;
        String sql = "select max(" + fieldName + ")as MaxId  from " + tableName;
        Connection conn = null;
        Statement pst = null;
        Integer num = 0;
        try {
            conn = DataSourceUtil.getConnection(configuration);
            pst = conn.createStatement();
            ResultSet resultSet = pst.executeQuery(sql);
            while (resultSet.next()) {
//                num = resultSet.getInt(0);
                //注释了188行 新建189行     注释了198行  新加200-203行
                String maxId = resultSet.getString("MaxId");
                if (!"".equals(maxId) && maxId != null) {
                    num = Integer.valueOf(maxId);
                }
            }
            return num;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (pst != null && !pst.isClosed()) {
                    pst.close();
                }
                if (conn != null && !conn.isClosed()) {
                    conn.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return 0;
    }
}
